package lumis.service.rss;

import java.util.Collection;

import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.VariableResolver;

import lumis.doui.DouiManagerFactory;
import lumis.portal.PortalContext;
import lumis.portal.PortalException;
import lumis.portal.PortalRequestParameters;
import lumis.portal.UnexpectedException;
import lumis.portal.authentication.SessionConfig;
import lumis.portal.el.LumisExpressionEvaluatorImpl;
import lumis.portal.filesystem.PortalBaseFolder;
import lumis.portal.filesystem.PortalFile;
import lumis.portal.filesystem.PortalFilePath;
import lumis.portal.manager.ManagerException;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.manager.ManagerStringResource;
import lumis.portal.service.ServiceException;
import lumis.util.IResource;
import lumis.util.ITransaction;
import lumis.util.XmlUtil;

import org.w3c.dom.Node;

/**
 *	Implementation for the RSS manager.
 * 
 *	@since 4.1.0
 *	@version $Revision: 11470 $ $Date: 2010-04-29 12:39:58 -0300 (Thu, 29 Apr 2010) $
 */
public class RssManager implements IRssManager
{
	private IRssDao rssDao = new RssDao();
	private IResource stringsResource = new ManagerStringResource();
	
	public RssManager()
	{
		stringsResource.addResourcePath("lumis/service/rss/strings/strings");
	}
	
	public void generateRssXmlFile(SessionConfig sessionConfig, RssConfig rssConfig, String oldPath, ITransaction transaction) throws PortalException, ServiceException
	{
		try
		{
			prepare(rssConfig, transaction);
			
			String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
			content += "<rss version=\"2.0\">";
			content += "<channel>";
			
			content += processHeader(rssConfig.getHeader());
			
			Collection<RssResultRow> rssResults = rssDao.getResults(rssConfig, transaction);

			for(RssResultRow resultsRow : rssResults)
			{
				content += "<item>";
				
				if(resultsRow.getTitle() != null)
					content += "<title>"+XmlUtil.encodeXml(resultsRow.getTitle())+"</title>";
				
				if(resultsRow.getDescription() != null)
					content += "<description>"+XmlUtil.encodeXml(resultsRow.getDescription())+"</description>";
				
				if(resultsRow.getLink() != null)
					content += "<link>"+XmlUtil.encodeXml(resultsRow.getLink())+"</link>";
				else
					content += "<link>"+XmlUtil.encodeXml(PortalContext.getFrameworkUrl() + 
							"/contenthyperlink.jsp?" + PortalRequestParameters.PAGE_PARAMETER_ITEM_ID + 
							"=" + resultsRow.getContentId())+"</link>";
				
				if(resultsRow.getPublishDate() != null)
					content += "<pubDate>"+XmlUtil.encodeXml(resultsRow.getPublishDate().toGMTString())+"</pubDate>";
				
				content += "</item>";
			}

			content += "</channel>";
			content += "</rss>";
			
			String relativePath = "/data/rss/" + rssConfig.getRssServiceInstanceId() + "/" + rssConfig.getId() + ".xml";
			
			if (rssConfig.getPath() != null && rssConfig.getPath().length() > 0)
				relativePath = "/data/rss/" + rssConfig.getPath();
				
			PortalFile portalFile = new PortalFile(new PortalFilePath(PortalBaseFolder.WWW, relativePath));
			ManagerFactory.getFileSystemManager().writeFile(portalFile, content.getBytes("UTF-8"));
			
			// delete old file if is necessary
			String relativeOldPath = "/data/rss/" + rssConfig.getRssServiceInstanceId() + "/" + rssConfig.getId() + ".xml";
			
			if (oldPath != null && oldPath.length() > 0)
				relativeOldPath = "/data/rss/" + oldPath;
			
			if (!relativePath.equals(relativeOldPath))
			{
				PortalFile fileOld = new PortalFile(new PortalFilePath(PortalBaseFolder.WWW, relativeOldPath));
				fileOld.delete();
			}
		}
		catch (PortalException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}
	
	protected String processHeader(String header) throws PortalException
	{
		try
		{
			if (header == null)
				return null;

			final LumisExpressionEvaluatorImpl evaluator = new LumisExpressionEvaluatorImpl();
			final VariableResolver variableResolver = new RssHeaderVariableResolver();

			return (String) evaluator.evaluate(header, String.class, variableResolver, null);
		}
		catch (ELException e)
		{
			throw new UnexpectedException(e);
		}
	}
	
	public RssConfig get(SessionConfig sessionConfig, String id, ITransaction transaction) throws PortalException
	{
		RssConfig rssConfig = rssDao.get(id, transaction);
		return rssConfig;
	}
	
	public Collection<String> getIdsByServiceInstanceId(SessionConfig sessionConfig, String serviceInstanceId, ITransaction transaction) throws PortalException
	{	
		return rssDao.getIdsByServiceInstanceId(serviceInstanceId, transaction);
	}
	
	/**
	 * Prepare data and validate to insert in table
	 * 
	 * @param rssConfig
	 * @param transaction
	 * @throws PortalException
	 * @since 4.1.0
	 */
	protected void prepare(RssConfig rssConfig, ITransaction transaction) throws PortalException
	{
		Node serviceDefinitionNode = DouiManagerFactory.getDouiManager().getDouiServiceDefinitionNode(rssConfig.getServiceId(), transaction);

		Node sourceNode = null;
		if(rssConfig.getSourceId() == null)
		{
			sourceNode = XmlUtil.selectSingleNode("service/sources/source", serviceDefinitionNode);

			if(sourceNode != null)
				rssConfig.setSourceId(XmlUtil.readAttributeString("id", sourceNode));
		}
		
		if (rssConfig.getSourceId() == null)
			throw new ManagerException("STR_NOT_FOUND_SOURCE", stringsResource);

		if(sourceNode == null)
			sourceNode = XmlUtil.selectSingleNode("service/sources/source[@id='"+rssConfig.getSourceId()+"']", serviceDefinitionNode);
		
		if(sourceNode == null)
			throw new ManagerException("STR_NOT_FOUND_SOURCE: "+rssConfig.getSourceId(), stringsResource);
		
		Node tableNode = XmlUtil.selectSingleNode("table", sourceNode);
		if (tableNode != null)
			rssConfig.setTableName(XmlUtil.getTextContent(tableNode));
		else
			throw new ManagerException("STR_NOT_FOUND_TABLE", stringsResource);
		
		rssConfig.setPrimaryKeyFieldId(getSourceFieldValue(sourceNode, null, "isPrimaryKey", "STR_NOT_FOUND_PRIMARY_KEY", true, true));
		rssConfig.setPubDateFieldId(getSourceFieldValue(sourceNode, rssConfig.getPubDateFieldId(), "isPublishStartDate", "STR_NOT_FOUND_PUBLISHED_DATE", false, true));
		rssConfig.setTitleFieldId(getSourceFieldValue(sourceNode, rssConfig.getTitleFieldId(), "isPrimaryName", "STR_NOT_FOUND_TITLE", true, true));
		rssConfig.setDescriptionFieldId(getSourceFieldValue(sourceNode, rssConfig.getDescriptionFieldId(), "isIntroduction", "STR_NOT_FOUND_DESCRIPTION", true, true));
		rssConfig.setServiceInstanceField(getSourceFieldValue(sourceNode, rssConfig.getServiceInstanceField(), "isPublishToServiceInstances", null, true, false));
	}
	
	protected String getSourceFieldValue(Node sourceNode, String fieldId, String fieldType, String errorMessage, boolean stored, boolean showError) throws PortalException
	{
		if (fieldId == null)
		{
			Node fieldNode = XmlUtil.selectSingleNode("fields/field[@"+fieldType+"='true']", sourceNode);
			if(fieldNode != null)
				fieldId = XmlUtil.readAttributeString("id", fieldNode);
			
			if (fieldId == null && showError)
			{		
				throw new ManagerException(errorMessage, stringsResource);
			}
			
			if (!stored)
				fieldId = null;
		}
		
		return fieldId;
	}
	
	public boolean validateUniqueFilePath(String filePath, String notIncludingRssId, ITransaction transaction) throws PortalException
	{
		return rssDao.validateUniqueFilePath(filePath, notIncludingRssId, transaction);
	}
}
